﻿using System.IO;
using System.Text;
using UnityEngine;

public static class EncodeStreamHelper
{
    public static void Encode(this Stream stream, Vector4 v)
    {
        stream.Encode((int)(v.x * 1000));
        stream.Encode((int)(v.y * 1000));
        stream.Encode((int)(v.z * 1000));
        stream.Encode((int)(v.w * 1000));
    }

    public static void Encode(this Stream stream, Vector3 v)
    {
        stream.Encode((int)(v.x * 1000));
        stream.Encode((int)(v.y * 1000));
        stream.Encode((int)(v.z * 1000));
    }

    public static void Encode(this Stream stream, Vector2 v)
    {
        stream.Encode((int)(v.x * 1000));
        stream.Encode((int)(v.y * 1000));
    }

    public static void Encode(this Stream stream, Color v)
    {
        stream.Encode((int)(v.r * 1000));
        stream.Encode((int)(v.g * 1000));
        stream.Encode((int)(v.b * 1000));
        stream.Encode((int)(v.a * 1000));
    }

    public static void Encode(this Stream stream, int value)
    {
        byte[] buffer = new byte[4];
        buffer[0] = (byte)(value & 0xFF);
        buffer[1] = (byte)((value >> 8) & 0xFF);
        buffer[2] = (byte)((value >> 16) & 0xFF);
        buffer[3] = (byte)(value >> 24);
        stream.Write(buffer, 0, buffer.Length);
    }

    public static void Encode(this Stream stream, long value)
    {
        byte[] buffer = new byte[8];
        buffer[0] = (byte)(value & 0xFF);
        buffer[1] = (byte)((value >> 8) & 0xFF);
        buffer[2] = (byte)((value >> 16) & 0xFF);
        buffer[3] = (byte)((value >> 24) & 0xFF);
        buffer[4] = (byte)((value >> 32) & 0xFF);
        buffer[5] = (byte)((value >> 40) & 0xFF);
        buffer[6] = (byte)((value >> 48) & 0xFF);
        buffer[7] = (byte)((value >> 56) & 0xFF);
        stream.Write(buffer, 0, buffer.Length);
    }

    public static void Encode(this Stream stream, uint value)
    {
        byte[] buffer = new byte[4];
        buffer[0] = (byte)(value & 0xFF);
        buffer[1] = (byte)((value >> 8) & 0xFF);
        buffer[2] = (byte)((value >> 16) & 0xFF);
        buffer[3] = (byte)(value >> 24);
        stream.Write(buffer, 0, buffer.Length);
    }

    public static void Encode(this Stream stream, string value)
    {
        //写入长度
        if (string.IsNullOrEmpty(value))
            value = string.Empty;
        byte[] writeBytes = Encoding.UTF8.GetBytes(value);
        stream.Encode(writeBytes.Length);
        stream.Write(writeBytes, 0, writeBytes.Length);
    }

    public static int DecodeInt(this Stream stream, byte[] buffer)
    {
        stream.Read(buffer, 0, 4);
        int v = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24);
        return v;
    }

    public static string DecodeString(this Stream stream, byte[] buffer)
    {
        stream.Read(buffer, 0, 4);
        int v = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24);
        stream.Read(buffer, 0, v);
        return Encoding.UTF8.GetString(buffer, 0, v);
    }

    public static byte ReadByte(this byte[] contents, ref int pos)
    {
        byte v = contents[pos];
        ++pos;
        return v;
    }

    public static void WriteInt(this byte[] contents,ref int pos,int v)
    {
        if(null != contents && pos + 4 <= contents.Length)
        {
            contents[pos] = (byte)(v & 0xFF);
            contents[pos + 1] = (byte)((v >> 8) & 0xFF);
            contents[pos + 2] = (byte)((v >> 16) & 0xFF);
            contents[pos + 3] = (byte)((v >>24) & 0xFF);
            pos += 4;
        }
    }

    public static void WriteUInt(this byte[] contents, ref int pos, uint v)
    {
        if (null != contents && pos + 4 <= contents.Length)
        {
            contents[pos] = (byte)(v & 0xFF);
            contents[pos + 1] = (byte)((v >> 8) & 0xFF);
            contents[pos + 2] = (byte)((v >> 16) & 0xFF);
            contents[pos + 3] = (byte)((v >> 24) & 0xFF);
            pos += 4;
        }
    }

    public static void WriteUShort(this byte[] contents, ref int pos, ushort v)
    {
        if (null != contents && pos + 2 <= contents.Length)
        {
            contents[pos] = (byte)(v & 0xFF);
            contents[pos + 1] = (byte)((v >> 8) & 0xFF);
            pos += 2;
        }
    }

    public static ushort ReadUShort(this byte[] contents, ref int pos)
    {
        if (null != contents && pos + 2 <= contents.Length)
        {
            int v = (contents[pos] | (contents[pos + 1] << 8));
            pos += 2;
            return (ushort)v;
        }
        return 0;
    }

    public static void WriteFloat(this byte[] contents, ref int pos, float fv)
    {
        int v = (int)(fv * 1000.0f);
        contents.WriteInt(ref pos, v);
    }

    public static void WriteVector3(this byte[] contents, ref int pos,Vector3 v)
    {
        contents.WriteInt(ref pos, (int)(v.x * 1000.0f));
        contents.WriteInt(ref pos, (int)(v.y * 1000.0f));
        contents.WriteInt(ref pos, (int)(v.z * 1000.0f));
    }

    public static void WriteFloatArray(this byte[] contents, ref int pos, float[] v)
    {
        for(int i = 0; i < v.Length;++i)
        {
            contents.WriteInt(ref pos, (int)(v[i] * 1000.0f));
        }
    }

    public static int ReadInt(this byte[] contents, ref int pos)
    {
        int v = contents[pos] | (contents[pos + 1] << 8) | (contents[pos + 2] << 16) | (contents[pos + 3] << 24);
        pos += 4;
        return v;
    }

    public static uint ReadUInt(this byte[] contents, ref int pos)
    {
        int v =((byte)contents[pos]) | (((byte)contents[pos + 1]) << 8) | (((byte)contents[pos + 2]) << 16) | (((byte)contents[pos + 3]) << 24);
        pos += 4;
        return (uint)v;
    }

    public static float ReadFloat(this byte[] contents, ref int pos)
    {
        return ReadInt(contents, ref pos) * 0.001f;
    }

    public static void ReadFloatArray(this byte[] contents, ref int pos,float[] v)
    {
        for(int i = 0; i < v.Length;++i)
        {
            v[i] = ReadInt(contents,ref pos) * 0.001f;
        }
    }

    public static Vector2 ReadVector2(this byte[] contents, ref int pos)
    {
        return new Vector2(ReadInt(contents, ref pos) * 0.001f, ReadInt(contents, ref pos) * 0.001f);
    }

    public static Vector3 ReadVector3(this byte[] contents, ref int pos)
    {
        return new Vector3(ReadInt(contents, ref pos) * 0.001f, ReadInt(contents, ref pos) * 0.001f, ReadInt(contents, ref pos) * 0.001f);
    }

    public static Vector4 ReadVector4(this byte[] contents, ref int pos)
    {
        return new Vector4(ReadInt(contents, ref pos) * 0.001f, ReadInt(contents, ref pos) * 0.001f, ReadInt(contents, ref pos) * 0.001f, ReadInt(contents, ref pos) * 0.001f);
    }

    public static Color ReadColor(this byte[] contents, ref int pos)
    {
        return new Vector4(ReadInt(contents, ref pos) * 0.001f, ReadInt(contents, ref pos) * 0.001f, ReadInt(contents, ref pos) * 0.001f, ReadInt(contents, ref pos) * 0.001f);
    }

    public static long ReadLong(this byte[] contents, ref int pos)
    {
        int key = ReadInt(contents, ref pos);
        long value = ReadInt(contents, ref pos);
        long val = ((value & 0xFFFFFFFF) << 32) | ((long)key);
        return val;
    }

    public static string ReadString(this byte[] contents, ref int pos)
    {
        int length = contents[pos] | (contents[pos + 1] << 8) | (contents[pos + 2] << 16) | (contents[pos + 3] << 24);
        pos += 4;
        string v = System.Text.Encoding.UTF8.GetString(contents, pos, length);
        pos += length;
        return v;
    }
}